package com.example.waterdispenserm2.mo.inductioncong;



import com.aill.androidserialport.SerialPort;
import android.content.Context;
import android.util.Log;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.InvalidParameterException;
import java.util.Arrays;

    /**
     * 电磁炉从机协议处理器 - 直接串口实现 (RS232/RS485/TTL/UART)
     * 严格遵循电磁炉单线通信协议
     *
     * 协议规范：
     * - 主机数据包：引导码(2ms低) + 0xA5 + 5字节显示码 + 1字节校验和（共7字节）
     * - 从机回复包：引导码(2ms低) + 1字节按键值 + 1字节取反校验（共2字节）
     * - 空闲电平：高电平
     * - 通信参数：9600波特率，8数据位，1停止位，无校验
     */

//一开始没实现  后加上  两个数据连着发
        public class InductionCookerSerialSlave {
            private static final String TAG = "CookerSerialSlave";

            // 协议常量
            public static final byte HOST_IDENTIFIER = (byte) 0xA5;
            private static final int HOST_PACKET_SIZE = 7;  // 主机数据包长度
            private static final int SLAVE_PACKET_SIZE = 2; // 从机回复包长度

            // 引导码相关计算
            private static final int BAUD_RATE = 9600;
            private static final int BITS_PER_BYTE = 10;    // 1起始位 + 8数据位 + 1停止位
            private static final int BREAK_BYTE_COUNT = calculateBreakByteCount(2.0); // 引导码2ms对应的字节数

            // 计算引导码需要的字节数
            private static int calculateBreakByteCount(double breakMs) {
                double bitTimeMs = 1000.0 / BAUD_RATE;  // 每位的持续时间(ms)
                double byteTimeMs = bitTimeMs * BITS_PER_BYTE; // 每字节的持续时间(ms)
                return (int) Math.ceil(breakMs / byteTimeMs);
            }

            // 段码表 (0-9, A-F) - 根据PDF协议文档重新定义
            public static final byte[] SEGMENT_CODES = {
                    (byte) 0x3F, // 0: seg_a | seg_b | seg_c | seg_d | seg_e | seg_f (0x3F)
                    (byte) 0x06, // 1: seg_b | seg_c (0x06)
                    (byte) 0x5B, // 2: seg_a | seg_b | seg_d | seg_e | seg_g (0x5B)
                    (byte) 0x4F, // 3: seg_a | seg_b | seg_c | seg_d | seg_g (0x4F)
                    (byte) 0x66, // 4: seg_b | seg_c | seg_f | seg_g (0x66)
                    (byte) 0x6D, // 5: seg_a | seg_c | seg_d | seg_f | seg_g (0x6D)
                    (byte) 0x7D, // 6: seg_a | seg_c | seg_d | seg_e | seg_f | seg_g (0x7D)
                    (byte) 0x07, // 7: seg_a | seg_b | seg_c (0x07)
                    (byte) 0x7F, // 8: seg_a | seg_b | seg_c | seg_d | seg_e | seg_f | seg_g (0x7F)
                    (byte) 0x6F, // 9: seg_a | seg_b | seg_c | seg_d | seg_f | seg_g (0x6F)
                    (byte) 0x77, // A: seg_a | seg_b | seg_c | seg_e | seg_f | seg_g (0x77)
                    (byte) 0x7C, // B: seg_c | seg_d | seg_e | seg_f | seg_g (0x7C)
                    (byte) 0x39, // C: seg_a | seg_d | seg_e | seg_f (0x39)
                    (byte) 0x5E, // D: seg_b | seg_c | seg_d | seg_e | seg_g (0x5E)
                    (byte) 0x79, // E: seg_a | seg_d | seg_e | seg_f | seg_g (0x79)
                    (byte) 0x71  // F: seg_a | seg_e | seg_f | seg_g (0x71)
            };

            // LED状态定义 - 根据PDF协议文档修正
            public static final byte LED_STEW = (byte) 0x01;       // 煲汤  bit0
            public static final byte LED_STEAM = (byte) 0x02;      // 蒸煮  bit1
            public static final byte LED_BOIL_WATER = (byte) 0x04; // 烧水  bit2
            public static final byte LED_LOW_FIRE = (byte) 0x08;   // 文火  bit3
            public static final byte LED_HIGH_FIRE = (byte) 0x10;  // 武火  bit4
            public static final byte LED_HOTPOT = (byte) 0x20;     // 火锅  bit5
            public static final byte LED_PORRIDGE = (byte) 0x40;   // 煲粥  bit6
            public static final byte LED_FRYING = (byte) 0x80;     // 炒菜  bit7

            // 按键定义
            public static final int KEY_NONE = 0;
            public static final int KEY_POWER = 1;      // 电量/电压
            public static final int KEY_TIMER = 2;      // 定时/预约
            public static final int KEY_DECREASE = 3;   // 减
            public static final int KEY_INCREASE = 4;    // 加
            public static final int KEY_FUNCTION = 5;    // 功能
            public static final int KEY_START = 6;       // 启动

            // 回调接口
            public interface ProtocolCallback {
                void onDisplayUpdate(int thousands, int hundreds, int tens, int units, byte ledStatus);
                void onKeySent(int keyCode);
                void onConnectionStatusChanged(boolean connected, String portPath);
                void onError(String errorMessage);
                void onDataReceived(byte[] data);
                void onDataSent(byte[] data);
            }

            // 成员变量
            private final Context context;
            private final ProtocolCallback callback;
            private SerialPort serialPort;
            private InputStream inputStream;
            private OutputStream outputStream;
            private ReadThread readThread;
            private int currentKeyCode = KEY_NONE;
            private boolean isConnected = false;
            private String currentPortPath;

            public InductionCookerSerialSlave(Context context, ProtocolCallback callback) {
                this.context = context;
                this.callback = callback;
            }

            /**
             * 连接到指定串口设备
             * @param portPath 串口设备路径 (e.g., "/dev/ttyS0")
             * @return true连接成功, false连接失败
             */
            public boolean connect(String portPath) {
                if (isConnected) {
                    disconnect();
                }

                try {
                    // 打开串口 (9600波特率，8数据位，1停止位，无校验)
                    serialPort = new SerialPort(new File(portPath), BAUD_RATE, 0);
                    inputStream = serialPort.getInputStream();
                    outputStream = serialPort.getOutputStream();

                    // 启动数据读取线程
                    readThread = new ReadThread();
                    readThread.start();

                    isConnected = true;
                    currentPortPath = portPath;
                    notifyConnectionStatus(true, portPath);
                    return true;
                } catch (SecurityException e) {
                    notifyError("无串口访问权限: " + portPath);
                } catch (IOException e) {
                    notifyError("打开串口失败: " + portPath + ", " + e.getMessage());
                } catch (InvalidParameterException e) {
                    notifyError("无效的串口参数: " + portPath);
                }
                return false;
            }

            /**
             * 断开连接并释放资源
             */
            public void disconnect() {
                if (readThread != null) {
                    readThread.interrupt();
                    try {
                        readThread.join(500);
                    } catch (InterruptedException e) {
                        // Ignore
                    }
                    readThread = null;
                }

                if (serialPort != null) {
                    serialPort.close();
                    serialPort = null;
                }

                try {
                    if (inputStream != null) {
                        inputStream.close();
                        inputStream = null;
                    }
                    if (outputStream != null) {
                        outputStream.close();
                        outputStream = null;
                    }
                } catch (IOException e) {
                    Log.w(TAG, "关闭流时出错", e);
                }

                isConnected = false;
                notifyConnectionStatus(false, currentPortPath);
                currentPortPath = null;
            }

            /**
             * 设置当前按键值（由UI调用）
             * @param keyCode 按键代码 (KEY_* 常量)
             */
            public void setCurrentKey(int keyCode) {
                this.currentKeyCode = keyCode;
            }

            /**
             * 数据读取线程 - 持续监听串口数据
             */
            private class ReadThread extends Thread {
                @Override
                public void run() {
                    super.run();
                    byte[] buffer = new byte[HOST_PACKET_SIZE];

                    while (!isInterrupted() && isConnected) {
                        try {
                            // 阻塞读取直到收到完整数据包
                            int bytesRead = 0;
                            while (bytesRead < HOST_PACKET_SIZE) {
                                int count = inputStream.read(
                                        buffer, bytesRead, HOST_PACKET_SIZE - bytesRead);
                                if (count < 0) {
                                    throw new IOException("串口读取终止");
                                }
                                bytesRead += count;
                            }

                            // 处理完整数据包
                            processReceivedData(Arrays.copyOf(buffer, HOST_PACKET_SIZE));

                        } catch (IOException e) {
                            notifyError("串口读取错误: " + e.getMessage());
                            disconnect();
                            break;
                        }
                    }
                }
            }

            /**
             * 处理接收到的数据（主机发送的协议帧）
             * @param data 7字节数据包
             */
            private void processReceivedData(byte[] data) {
                // 原始数据回调
                if (callback != null) callback.onDataReceived(data);

                // 协议要求：主机发送7字节数据包
                if (data.length != HOST_PACKET_SIZE) {
                    notifyError("数据长度错误: " + data.length + "字节");
                    return;
                }

                // 检查识别码 (协议位置[0])
                if (data[0] != HOST_IDENTIFIER) {
                    notifyError("无效的识别码: 0x" + String.format("%02X", data[0]));
                    return;
                }

                // 计算校验和 (协议要求：0xA5 + 5字节显示码的和，取低8位)
                int calculatedChecksum = 0;
                for (int i = 0; i < HOST_PACKET_SIZE - 1; i++) {
                    calculatedChecksum += data[i] & 0xFF; // 无符号加法
                }
                calculatedChecksum &= 0xFF; // 取低8位

                // 验证校验码 (协议位置[6])
                if ((byte) calculatedChecksum != data[6]) {
                    notifyError("校验失败: 计算值0x" + String.format("%02X", calculatedChecksum)
                            + " 接收值0x" + String.format("%02X", data[6]));
                    return;
                }

                // 解析显示数据 (协议位置[1]-[5])
                int thousands = findSegmentIndex(data[1]); // 千位
                int hundreds = findSegmentIndex(data[2]);  // 百位
                int tens = findSegmentIndex(data[3]);      // 十位
                int units = findSegmentIndex(data[4]);     // 个位
                byte ledStatus = data[5];                  // LED状态 (8个灯)

                // 回调显示更新
                if (callback != null) {
                    callback.onDisplayUpdate(thousands, hundreds, tens, units, ledStatus);
                }

                // 严格遵循协议：接收完主机数据后，延时4ms回复
                new Thread(() -> {
                    try {
                        Thread.sleep(4); // 精确延时4ms
                        sendKeyResponse(); // 发送按键响应
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                    }
                }).start();
            }

            /**
             * 根据段码值查找对应的数字索引
             * @param segment 段码值
             * @return 数字索引 (0-15对应0-9,A-F)
             */
            private int findSegmentIndex(byte segment) {
                for (int i = 0; i < SEGMENT_CODES.length; i++) {
                    if (SEGMENT_CODES[i] == segment) {
                        return i;
                    }
                }
                return 0; // 默认显示0
            }

            /**
             * 发送按键响应（从机回复协议帧）
             * 添加引导码处理逻辑
             */
            private synchronized void sendKeyResponse() {
                if (!isConnected || outputStream == null) {
                    notifyError("发送失败: 未连接");
                    return;
                }

                try {
                    // 构建协议帧：1字节数据码 + 1字节校验码（取反）
                    byte[] response = new byte[SLAVE_PACKET_SIZE];
                    response[0] = (byte) currentKeyCode;
                    response[1] = (byte) ~currentKeyCode; // 协议要求：数据码取反

                    // 创建引导码（连续低电平）
                    byte[] breakSignal = new byte[BREAK_BYTE_COUNT];
                    Arrays.fill(breakSignal, (byte) 0x00); // 全0产生连续低电平

                    // 发送引导码 + 响应数据
                    outputStream.write(breakSignal);
                    outputStream.write(response);
                    outputStream.flush();

                    // 回调发送事件（只报告协议数据，不包含引导码）
                    if (callback != null) {
                        callback.onDataSent(response);
                        callback.onKeySent(currentKeyCode);
                    }

                    // 重置按键值（避免重复发送）
                    currentKeyCode = KEY_NONE;
                } catch (IOException e) {
                    notifyError("发送按键失败: " + e.getMessage());
                }
            }

            // ================= 工具方法 ================= //

            /**
             * 获取按键名称
             * @param keyCode 按键代码
             * @return 按键名称
             */
            public static String getKeyName(int keyCode) {
                switch (keyCode) {
                    case KEY_POWER: return "电量/电压";
                    case KEY_TIMER: return "定时/预约";
                    case KEY_DECREASE: return "减";
                    case KEY_INCREASE: return "加";
                    case KEY_FUNCTION: return "功能";
                    case KEY_START: return "启动";
                    default: return "无按键";
                }
            }

            /**
             * 获取段码对应的显示字符
             * @param segment 段码值
             * @return 显示字符 (0-9, A-F)
             */
            public static String getSegmentChar(byte segment) {
                for (int i = 0; i < SEGMENT_CODES.length; i++) {
                    if (SEGMENT_CODES[i] == segment) {
                        return i < 10 ? String.valueOf(i) : String.valueOf((char) ('A' + i - 10));
                    }
                }
                return "?"; // 未知段码
            }

            /**
             * 获取LED状态描述
             * @param ledStatus LED状态字节
             * @return 激活的LED名称列表
             */
            public static String getActiveLeds(byte ledStatus) {
                StringBuilder sb = new StringBuilder();
                if ((ledStatus & LED_FRYING) != 0) sb.append("炒菜 ");
                if ((ledStatus & LED_PORRIDGE) != 0) sb.append("煲粥 ");
                if ((ledStatus & LED_HOTPOT) != 0) sb.append("火锅 ");
                if ((ledStatus & LED_HIGH_FIRE) != 0) sb.append("武火 ");
                if ((ledStatus & LED_LOW_FIRE) != 0) sb.append("文火 ");
                if ((ledStatus & LED_BOIL_WATER) != 0) sb.append("烧水 ");
                if ((ledStatus & LED_STEAM) != 0) sb.append("蒸煮 ");
                if ((ledStatus & LED_STEW) != 0) sb.append("煲汤 ");
                return sb.toString().trim();
            }

            // ================= 辅助方法 ================= //

            private void notifyConnectionStatus(boolean connected, String portPath) {
                if (callback != null) {
                    callback.onConnectionStatusChanged(connected, portPath);
                }
            }

            private void notifyError(String message) {
                Log.e(TAG, message);
                if (callback != null) {
                    callback.onError(message);
                }
            }

        }






